<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        .container {
            width: 100%;
            display: flex;
            display: -webkit-flex;
            justify-content: space-around;
            padding-top: 20px;
        }
        .video-box {
            position: relative;
            width: 800px;
            height: 400px;
        }
        #remote-video {
            width: 100%;
            height: 100%;
            display: block;
            object-fit: cover;
            border: 1px solid #eee;
            background-color: #F2F6FC;
        }
        #local-video {
            position: absolute;
            right: 0;
            bottom: 0;
            width: 240px;
            height: 120px;
            object-fit: cover;
            border: 1px solid #eee;
            background-color: #EBEEF5;
        }
        .start-button {
            position: absolute;
            left: 50%;
            top: 50%;
            width: 100px;
            display: none;
            line-height: 40px;
            outline: none;
            color: #fff;
            background-color: #409eff;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transform: translate(-50%, -50%);
        }
        .logger {
            width: 40%;
            padding: 14px;
            line-height: 1.5;
            color: #4fbf40;
            border-radius: 6px;
            background-color: #272727;
        }
        .logger .error {
            color: #DD4A68;
        }
    </style>
</head>
<body>

<textarea id="sendReceive">

</textarea>
<textarea id="dataReceive">

</textarea>
<input type="button" value="普通按钮"/>
<input type="button" id ="call"  onclick="call()" value = "连接" />

<input type="button" id ="send"  onclick="sendData()" value = "发送" />

<div class="logger"></div>
<script  >
    const message = {
        el: document.querySelector('.logger'),
        log (msg) {
            this.el.innerHTML += `<span>${new Date().toLocaleTimeString()}：${msg}</span><br/>`;
        },
        error (msg) {
            this.el.innerHTML += `<span class="error">${new Date().toLocaleTimeString()}：${msg}</span><br/>`;
        }
    };
    function  onAddIceCandidateError (pc, err) {
        message.log("添加" + pc + "       IceCandidate 失败" + err.toString())
    }

    function  onAddIceCandidateSuccess (pc) {
        message.log("添加" + pc + "      IceCandidate 成功")
    }
    function  call(){
        data.call()
    }
    function sendData(){
        data.sendData()
    }

    class DataChannel{


        constructor() {
        }

        sendData(){
            let sendReceive = document.getElementById("sendReceive");
            let data=sendReceive.value;

            this.sendChannel.send(data);
        }
        call=async() =>{

            //let configuration= {"iceServers":[{"url":"stun:stun.l.google.com:19302"}]}
            let configuration=    {
                "iceServers": [{"url": "stun:stun.1.google.com:19302"}]
            }
            // 本地链接
            this. localConnection =new RTCPeerConnection(configuration);
           this.localConnection.addEventListener("icecandidate",this.onIceCandidateA);


            // 发送数据通道
            this.sendChannel=this.localConnection.createDataChannel("dataChannel");


            // 远端链接
            this.remoteConnection =new RTCPeerConnection(configuration);
           this.remoteConnection.addEventListener("icecandidate",this.onIceCandidateB);



            // 监听状态
            this.remoteConnection.addEventListener("iceconnectionstatechange",this.receiveChannelCallback);
            this.localConnection.addEventListener("iceconnectionstatechange",this.onSendChannelStateChange);




            this.remoteConnection.ondatachannel=this.receiveChannelCallback;

            try {
                const  offer= await  this.localConnection.createOffer();
                await  this.onCreateOfferSuccess(offer);
                debugger
          /*      message.log('创建本地SDP');
                await this.localConnection.setLocalDescription(offer);

                message.log('接收到发送方SDP');
                await this.remoteConnection.setRemoteDescription(offer);

                message.log('创建接收方（应答）SDP');
                const answer = await this.remoteConnection.createAnswer();

                message.log('本地响应');
                debugger
                this.localConnection.setRemoteDescription(new RTCSessionDescription(answer));*/

            }catch (e){
                this.onCreateSessioDescriptionError(e)
            }

        }

         async onIceCandidateA (event) {
            let that = this

            try {
                if (event.candidate) {
                    // 直接交换candidate数据，就不需要通过信令服务器传送
                    await that.remoteConnection.addIceCandidate(event)
                    message.log("peerConnB IceCandidate----------")
                    message.log(event)
                    onAddIceCandidateSuccess(that.remoteConnection)
                }
            } catch (e) {
                onAddIceCandidateError(that.remoteConnection, e)
            }
             message.log("onIceCandidateA data:" + event.candidate)
        }
         async onIceCandidateB (event) {
            let that = this
            try {
                if (event.candidate) {
                    await that.localConnection.addIceCandidate(event.candidate)
                    message.log("peerConnA IceCandidate----------")
                    message.log(event)
                    onAddIceCandidateSuccess(that.localConnection)
                }
            } catch (e) {
                 onAddIceCandidateError(that.localConnection, e)
            }
             message.log("onIceCandidateB data:" + event.candidate)
        }
        onSendChannelStateChange =() =>{
            debugger
            const  readyState= this.sendChannel.readyState;

            message.log(`发送通道状态 ${readyState}`);
        }

        receiveChannelCallback=(event)=>{
            debugger
            this. receiveChannel = event.channel;
            this. receiveChannel.onmessage = this.onReceiveMessageCallBack;
            this. receiveChannel.onopen = this.onReceiveChannelStateChange;
            this. receiveChannel.onclose = this.onReceiveChannelStateChange;
        }
        onReceiveChannelStateChange =() =>{
            const  readyState= this.receiveChannel.readyState;
            message.log(`接受通道状态 ${readyState}`);
        }


        //接受数据事件
        onReceiveMessageCallBack =(event)=>{
            let dataReceive = document.getElementById("dataReceive");
            dataReceive.value=event.data;
        }

        // 连接成功
        onCreateOfferSuccess= async (desc)=>{
            debugger
            message.log(`localConnection创建Offer返回SDP信息\n${desc.sdp}`)

            let that = this
            // 设置连接描述
            message.log("peerConnA 创建offer返回得SDP信息", desc.sdp)
            message.log("设置peerConnA得本地描述start...")
            try {
                await that.localConnection.setLocalDescription(desc)
                message.log("设置peerConnA得本地描述成功")
            } catch (e) {
                message.log("设置peerConnA得本地描述错误：", e.toString())
            }

            message.log("设置peerConnB得远端描述 start")
            try {
                await that.remoteConnection.setRemoteDescription(desc)
                message.log("设置peerConnB得远端描述成功")

            } catch (e) {
                message.log("设置peerConnB得远端描述错误：", e.toString())
            }

            // 开始应答
            message.log("peerConnB创建应答 answer start")
            try {
                const answer = await that.remoteConnection.createAnswer()
                message.log("peerConnB创建应答成功")
                await that.onCreateAnswerSuccess(answer)
            } catch (e) {
                message.log("peerConnB创建应答错误：", e.toString())
            }


        }

        // 创建answer应答成功
         async onCreateAnswerSuccess (answer) {
            let that = this
             message.log("peerConnB创建应答answer数据：", answer)
             message.log("peerConnA与peerConnB交换应答answer信息 start")

            try {
                await that.remoteConnection.setLocalDescription(answer)
                message.log("设置peerConnB得本地answer 应答远端描述成功")

            } catch (e) {
                message.log("设置peerConnB得本地answer应答描述错误：", e.toString())
            }

            try {
                await that.localConnection.setRemoteDescription(answer)
                message.log("设置peerConnA得远端answer应答描述成功")

            } catch (e) {
                message.log("设置peerConnA得远端answer应答描述错误：", e.toString())
            }
        }

        onIceStateChangeA =()=>{

        }
        onIceStateChangeB =()=>{

        }
    }
    var  data=new DataChannel();

</script>
</body>
</html>
